﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
using System.Xml.Linq;
using vkUpploaderLib.Exceptions;
using vkUpploaderLib.HttpHelpers;
using vkUpploaderLib.Objects;
using vkUpploaderLib.Resourses;
using Newtonsoft.Json;

namespace vkUpploaderLib
{
    using Newtonsoft.Json.Linq;

    /// <summary>
    /// Invokes various methods of VK API
    /// </summary>
    public static class ApiHelper
    {
        const string BaseUrl = "http://api.vkontakte.ru/api.php";
        private const string ApiId = "2023445";
        private const string Key = "oZQE978ygv9UcxAD4n4N";

        public static List<Album> GetAlbumsForUserOrGroup(string groupId = null)
        {
            ParametersCollection parametersCollection = null;
            if (groupId != null)
            {
                parametersCollection  = new ParametersCollection();
                
                // "-" means we load photos for group, otherwise for user
                parametersCollection.Add("oid", "-" + groupId);
            }

            XDocument x = ExcecuteMethod(ApiMethods.GetAlbums, parametersCollection);
            XElement root = x.Root;
            ThrowIfError(root);
            List<Album> returnValue = new List<Album>();
            foreach (var node in root.Elements())
            {
                Album a = GetAlbum(node);
                returnValue.Add(a);
            }

            return returnValue;
        }
        private static void ThrowIfError(XElement root)
        {
            if (root.Name == "error")
            {
                throw new VkException(string.Format("{0}: {1}\n{2}: {3}", StringResources.Error,
                                                  root.Element("error_code").Value, StringResources.ErrorDescription,
                                                  root.Element("error_msg").Value), root.Element("error_code").Value);
            }
        }

        private static Album GetAlbum(XElement node)
        {
            Album a = new Album();
            a.Name = node.Element("title").Value;
            a.Id = node.Element("aid").Value;
            a.Thumb = node.Element("thumb_id").Value;
            int o;
            if (int.TryParse(node.Element("size").Value, out o))
            {
                a.Count = o;
            }
            return a;
        }

        public static Photo UploadImage(string fileName, string albumId, string groupId)
        {
            //4 steps to load image

            //Getting upload server
            string url = GetUploadUrl(albumId, groupId);

            //Http-Post upload G-code wrapper + Save method
            var xml = PostAndSave(url, fileName);

            //Getting photo's details
            Photo photo = GetPhotoDetailsFromUploadResponce(xml);

            return photo;
        }

        private static Photo GetPhotoDetails(string photoId, string albumId)
        {

            ParametersCollection param = new ParametersCollection();
            param.Add("uid", AuthHelper.UserID);
            param.Add("aid", albumId);

            param.Add("pids", photoId);

            var photoXmlDoc = ExcecuteMethod(ApiMethods.GetPhotoById, param);

            ThrowIfError(photoXmlDoc.Root);

            var photoXmlNode = photoXmlDoc.Root.Element("photo");

            Photo photo = new Photo(photoXmlNode);

            return photo;
        }

        private static Photo GetPhotoDetailsFromUploadResponce(XDocument xml)
        {
            Photo photo = new Photo(xml.Root.Element("photo"));
            return photo;
        }


        public static List<VkGroup> GetGroups()
        {
            int maxCount = 1000;
            int offset = 0;

            var groupsDoc = GetGroupsDocForOffset(offset, maxCount);
            ThrowIfError(groupsDoc.Root);

            var currentResult = GroupsHelper.Parse(groupsDoc.Root);
            var allResult = new List<VkGroup>(currentResult);
            
            // api only returns 1000 first groups, so merge them 9 times if user has 9000 groups
            while (currentResult.Count == maxCount)
            {
                offset += maxCount;
                groupsDoc = GetGroupsDocForOffset(offset, maxCount);
                currentResult = GroupsHelper.Parse(groupsDoc.Root);
                allResult.AddRange(currentResult);
            }

            return allResult;
        }

        private static XDocument GetGroupsDocForOffset(int offset, int count)
        {
            ParametersCollection param = new ParametersCollection();
            param.Add("uid", AuthHelper.UserID);
            param.Add("extended", "1");
            param.Add("filter", "admin");

            param.Add("offset", offset.ToString());
            param.Add("count", count.ToString());

            var groupsDoc = ExcecuteMethod(ApiMethods.GetGroups, param);
            return groupsDoc;
        }

        public static string GetOriginalUrl(string photoId, string albumId)
        {
            Photo photo = GetPhotoDetails(photoId, albumId);
            HrefExctractor exctractor = new HrefExctractor(AuthHelper.UserID, photoId);
            string url = exctractor.GetOriginalUrl(AuthHelper.UserID, photoId);
            return url;
        }

        private static XDocument PostAndSave(string url, string fileName)
        {
            string result = HttpPostUtil.HttpUploadFile(url, fileName, "file1", "image/jpeg", null);

            ParametersCollection saveCollection = ParseJsonString(result);
            var response = ExcecuteMethod(ApiMethods.PhotosSave, saveCollection);

            ThrowIfError(response.Root);

            return response;
        }

        private static string GetUploadUrl(string albumId, string groupId)
        {
            ParametersCollection parameters = new ParametersCollection();
            parameters.Add("aid", albumId);
            if (groupId != null)
            {
                parameters.Add("gid", groupId);
            }

            parameters.Add("save_big", "1");
            var doc = ExcecuteMethod(ApiMethods.GetUploadServer, parameters);
            var root = doc.Root;
            ThrowIfError(root);
            return root.Element("upload_url").Value;
        }

        private static ParametersCollection ParseJsonString(string jsonString)
        {
            JToken jsonDocument = JToken.Parse(jsonString);
            //t["server"].Value<string>();

            string server = jsonDocument["server"].Value<string>();
            string photosList = jsonDocument["photos_list"].Value<string>();
            string photo = photosList;
            string album = jsonDocument["aid"].Value<string>();
            string hash = jsonDocument["hash"].Value<string>();

            JToken groupValue = jsonDocument["gid"];
            string gid = null;
            if (groupValue != null)
            {
                gid = groupValue.Value<string>();
            }

            ParametersCollection saveCollection = new ParametersCollection();
            saveCollection.Add("aid", album);
            saveCollection.Add("server", server);
            saveCollection.Add("photos_list", photo);
            saveCollection.Add("hash", hash);
            if (gid != null)
            {
                saveCollection.Add("gid", gid);
            }

            saveCollection.Add("save_big", "1");
            return saveCollection;
        }


        public static XDocument ExcecuteMethod(string method, ParametersCollection parameters = null)
        {
            WebClient wc = new WebClient();
            string url = string.Format(" https://api.vkontakte.ru/method/{0}.xml?uid={1}&access_token={2}&{3}", method, AuthHelper.UserID, AuthHelper.Token, parameters != null ? parameters.ToString() : String.Empty);
            StreamReader sr = new StreamReader(wc.OpenRead(url));
            string contents = sr.ReadToEnd();
            return XDocument.Parse(contents);
        }

        public static Album CreateNewAlbum(int viewPermission, int commentPermission, string name, string groupId)
        {
            ParametersCollection parametersCollection = new ParametersCollection();

            parametersCollection.Add("title", name);
            parametersCollection.Add("privacy", viewPermission.ToString());
            parametersCollection.Add("comment_privacy", commentPermission.ToString());
            if (groupId != null)
            {
                parametersCollection.Add("gid", groupId.ToString());
            }

            var doc = ExcecuteMethod(ApiMethods.CreateAlbum, parametersCollection);
            var root = doc.Root;
            ThrowIfError(root);
            return GetAlbum(root.Element("album"));
        }
    }
}


